#pragma once
#include <memory>
#include <set>
#include <boost/signals2.hpp>
#include <nice2d/entity.h>
#include <nice2d/imageset.h>

class Sprite : public Entity
{
    DECLARE_OBJECT(Sprite)
public:
    static SpritePointer create(const std::string &image, const sf::Vector2f &center);
public:
    Sprite();
    virtual ~Sprite();
public:
    void setSpriteOwner(SpritePointer owner);
    SpritePointer getSpriteOwner()const;
public:
    void setSpriteColor(const sf::Color &color);
    sf::Color getSpriteColor()const;

    void select();
    boost::signals2::signal<void(std::shared_ptr<Sprite>)> selected;
    void unselect();
    boost::signals2::signal<void(std::shared_ptr<Sprite>)> unselected;
    bool isSelected()const;
public:
    void setSpriteController(std::shared_ptr<SpriteController> controller);
    std::shared_ptr<SpriteController> getSpriteController()const;

    void addSpriteImage(const std::string &file, const sf::IntRect &area = sf::IntRect());
    void setSpriteImageSet(std::shared_ptr<ImageSet> imageset);

    void addDecorator(SpriteDecoratorPointer spriteDecorator);
    void clearDecorator();

    virtual PTree serialize() override;
    virtual void deserialize(const PTree &node) override;
protected:
    void onUpdateEntity(float deltaTime) override;
    virtual void onUpdateSprite(float deltaTime);

    void onDrawEntity(sf::RenderTarget &target, sf::RenderStates states) const override;
    virtual void onDrawSprite(sf::RenderTarget &target, sf::RenderStates states) const;
    virtual void onSpriteColorChanged();
    virtual void onSpriteStatusChanged();
    virtual void onControllableChanged();

    virtual void onPositionChanged() override;
    virtual void onSizeChanged() override;
    virtual void onRotateChanged() override;
    virtual void onScaleChanged() override;

    virtual void onOwnerChanged();
private:
    std::unique_ptr<class SpriteData> data;
};

using SpriteWeakPointer = std::weak_ptr<Sprite>;
using SpriteList = std::list<SpritePointer>;
using SpriteSet = std::set<SpritePointer>;
